package tiku_service

import (
	"encoding/json"
	"fmt"
	"github.com/go-redis/redis"
	"peilian-api/app/global/common"
	"peilian-api/app/global/databases/tables"
	"peilian-api/app/global/errors"
	"peilian-api/app/global/log"
	"peilian-api/app/global/variable"
	"peilian-api/app/model"
	"peilian-api/app/services/yf_service"
	"peilian-api/utils/paginate"
	"peilian-api/utils/tools"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

var createTaskRedisKey = "3d_create_%s_%d"

type TikuService struct{}

func (ts *TikuService) QueryFilter(tlr model.TikuListReq) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if tlr.Source != 0 {
			db = db.Where("source=?", tlr.Source)
		} else {
			db = db.Where("source in (1, 2)")
		}
		if tlr.Level != "" {
			db = db.Where("level=?", tlr.Level)
		}
		if tlr.ProfessionId != nil {
			db = db.Where("profession_id=?", *tlr.ProfessionId)
		}
		if tlr.SkillTag != "" {
			skillTagLi := strings.Split(tlr.SkillTag, ",")
			tagQuesQuery := variable.DB.MySQL.Model(&tables.CriteriaRelation{}).
				Select("QuestionID").Where("criteria_id in (?)", skillTagLi)
			db = db.Where("id in (?)", tagQuesQuery)
		}
		if tlr.UserId != 0 {
			user, _ := tables.GetUserInfoById(int(tlr.UserId)) //已验证用户存在，必定能查到
			userSubQuery := variable.DB.MySQL.Model(&tables.Roles{}).Select("UserId").Where("level>=?", user.Level)
			db = db.Where("user_id in (0, ?) or user_id in (?) or user_id is null", tlr.UserId, userSubQuery)
		}
		if tlr.VideoStatus != nil {
			db = db.Where("video_status=?", tlr.VideoStatus)
		}
		return db
	}
}
func (ts *TikuService) GetTIkuList(ctx *gin.Context, tlr model.TikuListReq) (int64, interface{}, *errors.ErrRes) {
	allQuestions := make([]*tables.QuestionResp, 0)
	uid, exists := ctx.Get("uid")
	id, _ := uid.(uint)
	if !exists {
		return 0, allQuestions, errors.NewErrInfo(10001, fmt.Errorf("您无权操作"))
	}
	tlr.UserId = id
	allQuery := variable.DB.MySQL.Model(&tables.Question{}).Scopes(ts.QueryFilter(tlr))
	var count int64
	if err := allQuery.Count(&count).Error; err != nil {
		return 0, allQuestions, errors.NewErrInfo(10002, err)
	}
	if err := allQuery.Preload("Profession").Scopes(paginate.Paginate(ctx.Request)).Order("-id").Find(&allQuestions).Error; err != nil {
		return 0, allQuestions, errors.NewErrInfo(10003, err)
	}
	for _, q := range allQuestions {
		q.SkillTagIds = make([]*tables.Criteria, 0)
		if err := variable.DB.MySQL.Model(&q.Question).
			Association("SkillTags").Find(&q.SkillTagIds); err != nil {
			continue
		}
	}
	return count, allQuestions, nil

}

func (ts *TikuService) DeleteTikuById(ctx *gin.Context, ti model.TikuId) *errors.ErrRes {
	// 查询该角色是否被使用
	_, exists := ctx.Get("uid")
	if !exists {
		return errors.NewErrInfo(10001, fmt.Errorf("您无权操作"))
	}
	tid := ti.Id
	questions, err := new(tables.Question).GetQuestionsByWhereMap(map[string]interface{}{"id": tid})
	if err != nil || len(questions) > 1 {
		return errors.NewErrInfo(10001, fmt.Errorf("题目删除失败，请重新尝试"))
	}
	//if err != nil || len(questions) > 1 || questions[0].User_id ==  {
	//	return errors.NewErrInfo(10001, fmt.Errorf("题目删除失败，请重新尝试"))
	//}
	//if len(users) != 0 && users[0].ID != 0 {
	//	return errors.NewErrInfo(10002, fmt.Errorf("该角色已绑定账号，不允许删除"))
	//}
	//
	//if _, err := roleObj.DeleteRolesById(int(ri.Id)); err != nil {
	//	return errors.NewErrInfo(10003, fmt.Errorf("角色删除失败，请重新尝试"))
	//}
	return nil
}

func (ts *TikuService) UpdateTikuList(ctx *gin.Context, tlu *tables.Question) *errors.ErrRes {
	// 1. 获取该用户的id
	_, exists := ctx.Get("uid")
	if !exists {
		return errors.NewErrInfo(10001, fmt.Errorf("您无权操作"))
	}

	qId := ctx.Param("id")
	if err := variable.DB.MySQL.Transaction(func(tx *gorm.DB) error {
		_ = tlu.SetCustomKeyWords()
		result := variable.DB.MySQL.Model(&tables.Question{}).Where("id=?", qId).Updates(tlu)
		if result.Error != nil {
			return result.Error
		}
		if result.RowsAffected <= 0 {
			return fmt.Errorf("没找到这条记录")
		}
		if tlu.ProfessionId != nil {
			p, err := tables.GetProfessionById(*tlu.ProfessionId)
			if err != nil || p.ID == 0 {
				return fmt.Errorf("find Profession error:%+v", err)
			}
		}

		if tlu.SkillTagIds != nil {
			qIdInt, err := strconv.Atoi(qId)
			if err != nil {
				return err
			}
			if err := variable.DB.MySQL.Delete(&tables.CriteriaRelation{}, "question_id=?", qId).Error; err != nil {
				return err
			}
			TagQuestionLi := make([]*tables.CriteriaRelation, 0)
			for _, tagId := range tlu.SkillTagIds {
				TagQuestionLi = append(TagQuestionLi, &tables.CriteriaRelation{
					QuestionID: uint(qIdInt),
					CriteriaID: tagId,
				})
			}
			if err := variable.DB.MySQL.Create(&TagQuestionLi).Error; err != nil {
				return err
			}
		}
		return nil
	}); err != nil {
		return errors.NewErrInfo(10002, err)
	}
	return nil
}

// 有时陪练发送消息生成视频
func (ts *TikuService) GenerateVideo(ctx *gin.Context, id uint, text string) *errors.ErrRes {
	var QueObj = new(tables.Question)
	questions, err := QueObj.GetQuestionsByWhereStr(fmt.Sprintf("id = %d", id))
	if err != nil {
		return errors.NewErrInfo(30000, fmt.Errorf("get question db is error"))
	}
	if len(questions) == 0 {
		return errors.NewErrInfo(30001, fmt.Errorf("get question db is empty"))
	}
	question := questions[0]

	if len(text) == 0 {
		text = questions[0].Text
	}
	if strings.TrimSpace(text) == "" {
		variable.DB.MySQL.Delete(&tables.Question{}, "id=?", question.ID)
		return nil
	}
	// 生成横屏
	taskId, err := CreateTask(text, "h")
	if err != nil {
		log.Logger.Error(fmt.Sprintf("create 3d create id:%d, error:%+v", question.ID, err))
		return errors.NewErrInfo(30002, fmt.Errorf("Regenerate video failed"))
	}
	redisKey := fmt.Sprintf(createTaskRedisKey, "h", question.ID)
	variable.DB.Redis.Set(redisKey, taskId, time.Hour)
	// 生成横屏
	taskId, err = CreateTask(text, "s")
	if err != nil {
		log.Logger.Error(fmt.Sprintf("create 3d create id:%d, error:%+v", question.ID, err))
		return errors.NewErrInfo(30002, fmt.Errorf("Regenerate video failed"))
	}
	redisKey = fmt.Sprintf(createTaskRedisKey, "s", question.ID)
	variable.DB.Redis.Set(redisKey, taskId, 10*time.Minute)

	//var msgReq = model.MsgInfo{Id: id, Text: text}
	//b, _ := json.Marshal(msgReq)
	//ret, err := new(yf_service.YfApi).SendMsg(ctx, variable.Config.Yf.TopicYoushi, yf_service.GenerateVideoCreateType, string(b))
	//if err != nil {
	//	return errors.NewErrInfo(30002, fmt.Errorf("Regenerate video failed"))
	//}
	//var smr model.SendMsgResp
	//json.Unmarshal([]byte(ret), &smr)
	//if !smr.SendStatus {
	//	return errors.NewErrInfo(30003, fmt.Errorf("Regenerate video failed"))
	//}
	new(tables.Question).UpdateQuestionsById(map[string]interface{}{"video_status": 3}, int(question.ID)) //生成中
	return nil
}

// 有时视频生成
func (ts *TikuService) GenerationVideoFinish(ctx *gin.Context, gvfr model.GenerateVideoFinishReq) error {
	var videoFinishData model.GenerateVideoFinishData
	json.Unmarshal([]byte(gvfr.Message), &videoFinishData)

	// 1. 先查询该数据是否存在
	var question tables.Question
	var count int64 = 0
	dbObj := variable.DB.MySQL.Model(&question)
	dbObj.Where("id = ?", videoFinishData.Id).Find(&question).Count(&count)
	if count != 0 {
		err := new(tables.Question).UpdateQuestionsById(map[string]interface{}{"video": videoFinishData.Video, "pc_video": videoFinishData.PcVideo, "video_status": 1}, int(videoFinishData.Id))
		if err != nil {
			return err
		}
	}

	return nil
}

// LoopGenerationVideoFinish 轮询视频生成信息
func (ts *TikuService) LoopGenerationVideoFinish(ctx *gin.Context) {
	defer func() {
		fmt.Println("LoopGenerationVideoFinish exit")
		if rErr := recover(); rErr != nil {
			fmt.Println(rErr)
		}
		tools.RecoverGoroutine()
		ts.LoopGenerationVideoFinish(ctx)
	}()

	Ques, _ := new(tables.Question).GetQuestionsByWhereStr("video = '' and pc_video = ''")
	for _, v := range Ques {
		redisKeyH := fmt.Sprintf(createTaskRedisKey, "h", v.ID)
		taskH, err := variable.DB.Redis.Get(redisKeyH).Result()
		if err != nil {
			if err == redis.Nil {
				ts.GenerateVideo(ctx, v.ID, "")
			}
			log.Logger.Error(fmt.Sprintf("redis get error:%+v", err))
			break
		}
		urlH, err := GetTask(taskH)
		if err != nil {
			log.Logger.Error(fmt.Sprintf("redis get task error:%+v", err))
			break
		}
		if urlH == "" {
			continue
		}
		redisKeyS := fmt.Sprintf(createTaskRedisKey, "s", v.ID)
		taskS, err := variable.DB.Redis.Get(redisKeyS).Result()
		if err != nil {
			if err == redis.Nil {
				ts.GenerateVideo(ctx, v.ID, "")
			}
			log.Logger.Error(fmt.Sprintf("redis get error:%+v", err))
			break
		}
		urlS, err := GetTask(taskS)
		if err != nil {
			log.Logger.Error(fmt.Sprintf("redis get task error:%+v", err))
			break
		}
		if urlS == "" {
			continue
		}
		err = new(tables.Question).UpdateQuestionsById(map[string]interface{}{"video": urlS, "pc_video": urlH, "video_status": 1}, int(v.ID))
		if err != nil {
			log.Logger.Error(fmt.Sprintf("update mysql error:%+v", err))
			break
		} else {
			variable.DB.Redis.Del(redisKeyH, redisKeyS)
		}
	}
	time.Sleep(time.Minute)
}

// 河北冀才网生成视频
func (ts *TikuService) HbGenerateVideo(ctx *gin.Context, hg model.HbGenerateVideo) (uint, *errors.ErrRes) {
	uid, exists := ctx.Get("uid")
	if !exists {
		return 0, errors.NewErrInfo(10001, fmt.Errorf("您无权操作"))
	}
	// 1. 取出数据插入到数据库中
	kw, _ := json.Marshal(hg.KeyWords)
	bid, _ := strconv.Atoi(hg.Bid)
	question := tables.Question{CareerID: 0, ParentText: "", Text: hg.Text, AnsAnalysis: hg.AnsAnalysis, KeyWords: string(kw), Bid: bid, Source: 3, Level: hg.Level, VideoStatus: 0, User_id: uid.(uint)}
	// 2. 判断问题是否存在
	var count int64 = 0
	var ques = tables.Question{}
	dbObj := variable.DB.MySQL.Model(&question)
	dbObj.Where("bid = ? and source = ?", bid, 3).Find(&ques).Count(&count)
	if count == 1 { // 说明数据已经存在
		question = ques
	} else {
		// 3. 创建一条记录
		err := dbObj.Create(&question).Error
		if err != nil {
			return 0, errors.NewErrInfo(30000, fmt.Errorf("insert question db is err"))
		}
	}

	// 4. 发送消息
	text := hg.Text
	id := question.ID

	var msgReq = model.MsgInfo{Id: id, Text: text}
	b, _ := json.Marshal(msgReq)
	ret, err := new(yf_service.YfApi).SendMsg(ctx, variable.Config.Yf.TopicYoushi, yf_service.GenerateVideoCreateType, string(b))
	if err != nil {
		return 0, errors.NewErrInfo(30002, fmt.Errorf("Regenerate video failed"))
	}
	var smr model.SendMsgResp
	json.Unmarshal([]byte(ret), &smr)
	if !smr.SendStatus {
		return 0, errors.NewErrInfo(30003, fmt.Errorf("Regenerate video failed"))
	}
	new(tables.Question).UpdateQuestionsById(map[string]interface{}{"video_status": 3}, int(id)) //生成中
	return id, nil
}

// 获取视频
func (ts *TikuService) GetGenerationVideo(ctx *gin.Context, gvfr model.HbGetGenerateVideo) (model.HbGenerateVideoResp, *errors.ErrRes) {
	var out = model.HbGenerateVideoResp{}
	gid, _ := strconv.Atoi(gvfr.Gid)
	bid, _ := strconv.Atoi(gvfr.Bid)
	sc := variable.DB.Redis.Get(fmt.Sprintf(common.RedisHbQuestionInfo, gid, bid))
	if sc.Err() != nil {
		return out, errors.NewErrInfo(30004, fmt.Errorf("Get video failed"))
	}
	s, _ := sc.Result()
	hgvr := model.HbGenerateVideoResp{}
	json.Unmarshal([]byte(s), &hgvr)
	if len(hgvr.Video) == 0 { // 查询一下数据库
		q, err := new(tables.Question).GetQuestionsByWhereStr(fmt.Sprintf("id = %d and bid = %d", gid, bid))
		if err != nil {
			return out, errors.NewErrInfo(30005, fmt.Errorf("get video is failed"))
		}
		if len(q) == 0 {
			return out, errors.NewErrInfo(30006, fmt.Errorf("get video is empty"))
		}
		if len(q[0].Video) == 0 {
			return out, errors.NewErrInfo(30007, fmt.Errorf("get video params is empty"))
		}
		out.Video = q[0].Video
	} else {
		out.Video = hgvr.Video
	}

	out.Text = hgvr.Text
	out.Bid = hgvr.Bid
	out.Gid = hgvr.Gid
	return out, nil
}

// 自定义职业 创建考试场次
func (ts *TikuService) CreateCustomCreate(ctx *gin.Context, cc model.HbCustomCreate) (uint, error) {
	careerName := cc.CareerName
	companyId := cc.CompanyId
	companyName := cc.CompanyName
	uid, exists := ctx.Get("uid")
	if !exists {
		return 0, fmt.Errorf("您无权操作")
	}

	var session tables.Session
	// 根据用户获取用户信息
	u, err := tables.GetUserInfoById(1)
	if err != nil {
		return 0, fmt.Errorf("fetch user fail")
	}
	if u.ID == 0 {
		return 0, fmt.Errorf("user is not exsit")
	}

	// 根据careerId 获取 career信息
	session.UserID = uid.(uint)
	session.CareerID = 45
	session.School = u.School
	session.Academy = u.Academy
	session.Profession = u.Profession
	session.Education = u.Education
	session.Grade = u.Grade
	session.UserName = u.Name
	session.UserPhone = u.Phone
	session.CareerName = careerName
	session.TrainAt = time.Now()
	session.Type = u.Type
	session.Sno = u.Sno
	session.IsSync = u.IsSync

	d := variable.DB.MySQL.Create(&session)
	if d.Error != nil {
		return 0, fmt.Errorf("插入失败")
	}
	sessionId := session.ID
	err = new(tables.Interview).InsertInterview(tables.Interview{SessionId: uint(sessionId), UserId: session.UserID, Phone: companyId, UserName: companyName})
	if err != nil {
		return sessionId, fmt.Errorf("错误分配面试间")
	}
	return sessionId, nil
}
